#include <stdio.h>
#include "sudoku_config.h"

extern char data[3][3][3][3];	/* data of current sudoku table */
extern char poss[3][3][3][3][9]; /* possibilities of current sudoku table */

/* init */
extern bool debug;
extern bool dummy;
extern bool collected;
extern bool arranged;
extern bool error;
extern bool put_value;

int init_poss()
{
    int i, j, k, l, m;
    int count = 0;

    for (i = 0; i < 3; i++) {
	for (j = 0; j < 3; j++) {
	    for (k = 0; k < 3; k++) {
		for (l = 0; l < 3; l++) {
		    for (m = 0; m < 9; m++) {
			poss[i][j][k][l][m] = (count++ % 9) +1;
		    }
		}
	    }
	}
    }
    collected = NO;
    return 0;
}

int remove_poss(int i, int j, int k, int l, char value)
{
    int m = 0;

    for (m = 0; m < 9; m++) {
	if (poss[i][j][k][l][m] == value) {
	    if (debug)
		printf("\nremoving %d from p[%d][%d][%d][%d][%d]", value, i, j, k, l, m);
	    collected = YES;
	    poss[i][j][k][l][m] = 0;
	    return 0;
	}
    }
    return -1;
}

int collect_poss()
{
    int i, j, k, l, m;
    int x, y;

    for (i = 0; i < 3; i++) {
	for (j = 0; j < 3; j++) {
	    for (k = 0; k < 3; k++) {
		for (l = 0; l < 3; l++) {
		    if (data[i][j][k][l] != 0)
			continue;
		    if (arranged && (poss[i][j][k][l][1] == 0))
			continue;
		    
		    x = k;
		    y = l;
		    for (x = 0; x < 3; x++) {
			for (y = 0; y < 3; y++) {
			    if (data[i][j][x][y] != 0)
				remove_poss(i, j, k, l, data[i][j][x][y]);
			}
		    }
		    
		    x = i;
		    y = j;
		    for (x = 0; x < 3; x++) {
			for (y = 0; y < 3; y++) {
			    if (data[x][y][k][l] != 0)
				remove_poss(i, j, k, l, data[x][y][k][l]);
			}
		    }

		    x = j;
		    y = l;
		    for (x = 0; x < 3; x++) {
			for (y = 0; y < 3; y++) {
			    if (data[i][x][k][y] != 0)
				remove_poss(i, j, k, l, data[i][x][k][y]);
			}
		    }
		}
	    }
	}
    }
    if (!collected)
	return -1;
    return 0;
}

int arrange_poss()
{
    int i, j, k, l, m;
    char to;
    
    for (i = 0; i < 3; i++) {
	for (j = 0; j < 3; j++) {
	    for (k = 0; k < 3; k++) {
		for (l = 0; l < 3; l++) {
		    to = 0;
		    for (m = 0; m < 9; m++) {
			if (poss[i][j][k][l][m] != 0) {
			    if (to == m) {
				to++;
				continue;
			    } else {
				poss[i][j][k][l][to] = poss[i][j][k][l][m];
				poss[i][j][k][l][m] = 0;
				to++;
				arranged = YES;
			    }
			} 
		    }
		}
	    }
	}
    }
    if (!arranged)
	return -1;
    return 0;
}

int make_poss_zero(int i, int j, int k, int l)
{
    int m;

    for (m = 0; m < 9; m++) {
	poss[i][j][k][l][m] = 0;
    }
}

int all_poss_zero()
{
    int i, j, k, l, m;
    for (i = 0; i < 3; i++) {
	for (j = 0; j < 3; j++) {
	    for (k = 0; k < 3; k++) {
		for (l = 0; l < 3; l++) {
		    if (data[i][j][k][l] != 0) {
			for (m = 0; m < 9; m++) {
			    poss[i][j][k][l][m] = 0;
			}
		    }
		}
	    }
	}
    }
}

int set_value()
{
    int i, j, k, l, m;
    int x;
    int p, q, r, s;
    int temp, t;
    bool is_there = NO;
    put_value = NO;
    
    arrange_poss();

    for (i = 0; i < 3; i++) {
	for (j = 0; j < 3; j++) {
	    for (k = 0; k < 3; k++) {
		for (l = 0; l < 3; l++) {
		    
		    if (data[i][j][k][l] != 0)
			continue;

		    if (poss[i][j][k][l][1] == 0) {
			if (poss[i][j][k][l][0] == 0)
			    continue;
		    	data[i][j][k][l] = poss[i][j][k][l][0];
		    	if (arrange_poss())
			    printf("arrange not good\n");
		    	printf("SET:data[%d][%d][%d][%d] = %d\n", i, j, k, l, data[i][j][k][l]);
			//			make_poss_zero(i, j, k, l);
			poss[i][j][k][l][0] = 0;
			//		    	poss[i][j][k][l][0] = 0;
		    	put_value = YES;
		    	continue;
		    }

		    if (debug)
			printf("Entering Setting value\n");
		    for (x = 0; poss[i][j][k][l][x]; x++) {
			temp = poss[i][j][k][l][x];
			HARC:			
			if (debug)
			    printf("Horizontal Setting is going on\n");
			is_there = NO;
			p = i;
			q = j;
			r = k;
			s = l;
			for (r = 0; r < 3; r++) {
			    for (s = 0; s < 3; s++) {
				if (r == k && s == l) {
				    continue;
				}
				if (data[p][q][r][s] != 0) {
				    if (data[p][q][r][s] == temp)
					goto NEXT_POSS;
				    continue;
				}
				for (t = 0; poss[p][q][r][s][t]; t++) {
				    if (temp == poss[p][q][r][s][t]) {
					is_there = YES;
					goto VERC;
				    }
				}
			    }
			}
			if (is_there == NO) {
			    if (poss[i][j][k][l][x] == 0)
				continue;
			    data[i][j][k][l] = poss[i][j][k][l][x];
			    if (check(i, j, k, l, poss[i][j][k][l][x]))
				    printf("goiyala\n");
			    make_poss_zero(i, j, k, l);
			    printf("HARC:data[%d][%d][%d][%d] = %d\n", i, j, k, l, data[i][j][k][l]);

			    arrange_poss();
			    goto NEXT;
			}

			VERC:			
			if (debug)
			    printf("Vertical Setting is going on\n");
			is_there = NO;
			p = i;
			q = j;
			r = k;
			s = l;
			
			for (p = 0; p < 3; p++) {
			    for (q = 0; q < 3; q++) {
				if (p == i && q == j) {
				    continue;
				}
				if (data[p][q][r][s] != 0) {
				    if (data[p][q][r][s] == temp)
					goto NEXT_POSS;
				    continue;
				}
				for (t = 0; poss[p][q][r][s][t]; t++) {
				    if (temp == poss[p][q][r][s][t]) {
					is_there = YES;
					goto PARC;
				    }
				}
			    }
			}
			if (is_there == NO) {
			    if (poss[i][j][k][l][x] == 0)
				goto PARC;
			    data[i][j][k][l] = poss[i][j][k][l][x];
			    make_poss_zero(i, j, k, l);
			    printf("VERC:data[%d][%d][%d][%d] = %d\n", i, j, k, l, data[i][j][k][l]);
			    arrange_poss();
			    goto NEXT;
			}
			PARC:			
			if (debug)
			    printf("Paragraph Setting is going on\n");
			is_there = NO;
			p = i;
			q = j;
			r = k;
			s = l;
			
			for (q = 0; q < 3; q++) {
			    for (s = 0; s < 3; s++) {
				if (q == j && s == l) {
				    continue;
				}
				if (data[p][q][r][s] != 0) {
				    if (data[p][q][r][s] == temp)
					goto NEXT_POSS;
				    continue;
				}
				for (t = 0; poss[p][q][r][s][t]; t++) {
				    if (temp == poss[p][q][r][s][t]) {
					is_there = YES;
					goto NEXT_POSS;
				    }
				}
			    }
			}
			if (is_there == NO) {
			    if (poss[i][j][k][l][x] == 0)
				goto PARC;
			    data[i][j][k][l] = poss[i][j][k][l][x];
			    make_poss_zero(i, j, k, l);
			    printf("PARC:data[%d][%d][%d][%d] = %d\n", i, j, k, l, data[i][j][k][l]);
			    arrange_poss();
			    goto NEXT;
			}
			NEXT_POSS:
			;
		    }
		    NEXT:
		    ;
		}
	    }
	}
    }
    if (put_value)
	return 0;
    return -1;
}


int poss_process()
{
    int count = 0;

    int k = 5;

    while (k--) {

    init_poss();
    while (1) {

	if (collect_poss()) {
	    printf("There is nothing to collect!!\n");
	    break;
	}
	if (debug)
	    printf("collected %d\n", count++);
	put_value = NO;

	all_poss_zero();

	if (arrange_poss()) {
	    printf("There is nothing to arrange!!\n");
	}
	if (debug)
	    printf("arranged %d\n", count++);
	collected = NO;	

	all_poss_zero();

	if (set_value()) {
	    printf("There is nothing to Set!!\n");
	    break;
	}
	if (debug)
	    printf("set value %d\n", count++);
	arranged = NO;
	
	all_poss_zero();


//		data[2][0][2][2] = 8;
    }
    great_poss();
    printf ("kathir: %d\n", k);
    }
}


int great_poss()
{
    int i, j, k, l, m;
    int p, q, r, s;
    int a, b, c, d;
    int count;
    int current_count;

    printf("before_great_poss\n");
    show_struct_poss();

    arrange_poss();
    for (i = 0; i < 3; i++) {
	for (j = 0; j < 3; j++) {
	    for (k = 0; k < 3; k++) {
		for (l = 0; l < 3; l++) {

		    for (count = 0; poss[i][j][k][l][count]; count++) {
			if (count > 2)
			    goto NEXT_BIG_NAVI;
		    }

		    HARCC:
		    p = i;
		    q = j;
		    r = k;
		    s = l;
		    current_count = 1;
		    for (r = 0; r < 3; r++) {
			for (s = 0; s < 3; s++) {
			    if (r == k && s == l)
				continue;
			    if (data[p][q][r][s] != 0)
				continue;
			    for (m = 0; poss[i][j][k][l][m]; m++) {
				if (poss[i][j][k][l][m] != poss[p][q][r][s][m])
				    goto NEXT_HARCC_NAVI;
			    }
			    /* current_count++; */
			    /* if (count != current_count) */
			    /* 	continue; */

			    /* start_clear  (HAR) */
			    a = i;
			    b = j;
			    c = k;
			    d = l;
			    
			    for (c = 0; c < 3; c++) {
				for (d = 0; d < 3; d++) {
				    if ((c == r && d == s) || (c == k && d == l))
					continue;
				    for (m = 0; poss[i][j][k][l][m]; m++) {
					remove_poss(a, b, c, d, poss[i][j][k][l][m]);
				    }
				}
			    }
			    arrange_poss();
			}
			NEXT_HARCC_NAVI:
			;
		    }
		    VERCC:		    
		    p = i;
		    q = j;
		    r = k;
		    s = l;
		    current_count = 1;
		    for (p = 0; p < 3; p++) {
			for (q = 0; q < 3; q++) {
			    if (p == i && q == j)
				continue;
			    if (data[p][q][r][s] != 0)
				continue;
			    for (m = 0; poss[i][j][k][l][m]; m++) {
				if (poss[i][j][k][l][m] != poss[p][q][r][s][m])
				    goto NEXT_VERCC_NAVI;
			    }
			    /* current_count++; */
			    /* if (count != current_count) */
			    /* 	continue; */

			    /* start_clear  (VER) */
			    a = i;
			    b = j;
			    c = k;
			    d = l;
			    
			    for (a = 0; a < 3; a++) {
				for (b = 0; b < 3; b++) {
				    if ((a == p && b == q) || (a == i && b == j))
					continue;
				    for (m = 0; poss[i][j][k][l][m]; m++) {
					remove_poss(a, b, c, d, poss[i][j][k][l][m]);
				    }
				}
			    }
			    arrange_poss();
			}
			NEXT_VERCC_NAVI:
			;
		    }
		    PARCC:
		    p = i;
		    q = j;
		    r = k;
		    s = l;
		    current_count = 1;
		    for (q = 0; q < 3; q++) {
			for (s = 0; s < 3; s++) {
			    if (q == j && s == l)
				continue;
			    if (data[p][q][r][s] != 0)
				continue;
			    for (m = 0; poss[i][j][k][l][m]; m++) {
				if (poss[i][j][k][l][m] != poss[p][q][r][s][m])
				    goto NEXT_PARCC_NAVI;
			    }
			    /* current_count++; */
			    /* if (count != current_count) */
			    /* 	continue; */

			    /* start_clear  (PAR) */
			    a = i;
			    b = j;
			    c = k;
			    d = l;
			    
			    for (b = 0; b < 3; b++) {
				for (d = 0; d < 3; d++) {
				    if ((b == q && d == s) || (b == j && d == l))
					continue;
				    for (m = 0; poss[i][j][k][l][m]; m++) {
					remove_poss(a, b, c, d, poss[i][j][k][l][m]);
				    }
				}
			    }
			    arrange_poss();
			}
			NEXT_PARCC_NAVI:
			;
		    }
		    NEXT_BIG_NAVI:
		    ;
		}
	    }
	}
    }
    printf("after_great_poss\n");
    show_struct_poss();
}


int check(int a, int b, int c, int d, int value)
{
    int i, j, k, l;

    if (value == 0)
	return -1;
    i = a;
    j = b;
    k = c;
    l = d;
    for (k = 0; k < 3; k++) {
	for (l = 0; l < 3; l++) {
	    if (k == c && l == d)
		continue;
	    if (data[i][j][k][l] == value)
		return -1;
	}
    }


    i = a;
    j = b;
    k = c;
    l = d;
    for (i = 0; i < 3; i++) {
	for (j = 0; j < 3; j++) {
	    if (i == a && j == b)
		continue;
	    if (data[i][j][k][l] == value)
		return -1;
	}
    }


    i = a;
    j = b;
    k = c;
    l = d;
    for (j = 0; j < 3; j++) {
	for (l = 0; l < 3; l++) {
	    if (j == b && l == d)
		continue;
	    if (data[i][j][k][l] == value)
		return -1;
	}
    }

    return 0;

}


int is_completed()
{
    int i, j, k, l;

    for (i = 0; i < 3; i++) {
	for (j = 0; j < 3; j++) {
	    for (k = 0; k < 3; k++) {
		for (l = 0; l < 3; l++) {
		    if (data[i][j][k][l] == 0)
			return -1;
		}
	    }
	}
    }

    return 0;
}
